package com.wzcl.app.service.impl;

import com.alibaba.fastjson.JSON;
import com.wzcl.app.config.RabbitMqConfiguration;
import com.wzcl.app.dao.model.*;
import com.wzcl.app.dao.repository.AppUserRepository;
import com.wzcl.app.dao.repository.OrdersRepository;
import com.wzcl.app.model.common.*;
import com.wzcl.app.model.dto.CartDto;
import com.wzcl.app.model.dto.IosOrdersDto;
import com.wzcl.app.model.dto.OrdersDto;
import com.wzcl.app.model.dto.WorkShowDto;
import com.wzcl.app.service.*;
import com.wzcl.app.service.common.MyPayService;
import com.wzcl.app.service.common.PayServiceFactory;
import com.wzcl.app.utils.*;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.persistence.criteria.*;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;

@Log4j2
@Service
@Transactional
public class OrderServiceImpl implements OrderService {
    private static final String CREATE_LOCK = "ORDERS_CREATE_LOCK_";
    private static final String PAY_LOCK = "ORDERS_PAY_LOCK_";
    private static final String PAY_KEY = "ORDERS_PAY_KEY_";

    private static final String SECKILL_TYPE_KEY = "SECKILL";
    public static final String GROUP_TYPE_KEY = "GROUP";
    private static final String COMMON_TYPE_KEY = "COMMON";

    public static final String GROUP_PARAMETER_GROUP_ID = "GROUP_ID";
    public static final String GROUP_PARAMETER_PROMOTION_ID = "PROMOTION_ID";

    @Resource
    private OrdersRepository ordersRepository;
    @Resource
    private SendPathService sendPathService;
    @Resource
    private UserService userService;
    @Resource
    private CartService cartService;
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private AmqpTemplate amqpTemplate;
    @Resource
    private ActivityService activityService;
    @Resource
    private UserCourseService userCourseService;
    @Resource
    private CourseService courseService;
    @Resource
    private CommodityService commodityService;
    @Resource
    private SpecificationsService specificationsService;
    @Resource
    private ActivityGroupService activityGroupService;
    @Resource
    private AppUserRepository appUserRepository;

    //基本流程
    @Override
    public Orders addOrder(OrdersDto ordersDto) {
        //校验参数
        List<Cart> cartList = cartService.getCartById(ordersDto.getCartIdList());
        if (cartList == null || cartList.size() == 0) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "无有效商品信息,无法创建订单");
        }
        if (LockUtil.isLocked(CREATE_LOCK + ordersDto.getUserPhone())) {
            throw new BusinessException(CodeMsg.ORDER_CREATING);
        }
        LockUtil.lock(CREATE_LOCK + ordersDto.getUserPhone(), 5 * 60);
        try {
            AppUser user = userService.getAndCheckByPhone(ordersDto.getUserPhone());
            //创建基本订单
            Orders orders = createBasisOrders(user);
            orders.setCreateFrom(COMMON_TYPE_KEY);
            //设置系统类型
            orders.setSysType(ordersDto.getSysType());
            //计算所有活动和商品的价格
            List<OrderDetail> orderDetails = computeOrderDetails(orders, user, cartList.toArray(new Cart[0]));
            orders.setDetails(orderDetails);
            //计算结束
            orders = ordersRepository.save(orders);
            //生成唯一对应的支付记录
            //TODO 支付记录哈哈哈
            //payRecordService.initPayRecordByOrder(orders);
            //逻辑删除对应购物车(取消订单时可恢复)
            cartService.delCartByOrders(cartList, orders);
            //免费则发送支付回调
            if (BigDecimal.ZERO.compareTo(orders.getPayMoney()) == 0) {
                //TODO 支付记录哈哈哈
                /*PayRecord payRecord = new PayRecord();
                payRecord.setOrderNo(orders.getNo());
                payRecord.setPay(BigDecimal.ZERO);
                payRecord.setPayTime(new Date());
                payRecord.setPayType(WZCL.PAY_TYPE.FREE);
                payRecord.setPayState(WZCL.PAY_STATE.PAID);*/
                //amqpTemplate.convertAndSend(RabbitMqConfiguration.DIRECT_QUEUE_PAID, JSON.toJSONString(payRecord));
            } else {
                //设置过期时间
                amqpTemplate.convertAndSend(RabbitMqConfiguration.DELAY_QUEUE_ORDER, orders.getNo());
            }
            return orders;
        } catch (BusinessException businessException) {
            throw businessException;
        } catch (Exception e) {
            log.error("订单生成错误:{} \r\n 堆栈信息:{}", e.getMessage(), BusinessException.collectExceptionStackMsg(e));
            throw new BusinessException(CodeMsg.SYSTEM_ERR);
        } finally {
            LockUtil.unlock(CREATE_LOCK + ordersDto.getUserPhone());
        }
    }

    @Override
    public Orders addOrderEager(OrdersDto ordersDto) {
        //校验参数
        if (ordersDto == null || ordersDto.getCommodityId() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少商品Id");
        }
        //流程一致，先创建购物车
        CartDto cartDto = new CartDto();
        cartDto.setPhone(ordersDto.getUserPhone());
        cartDto.setCommodityId(ordersDto.getCommodityId());
        cartDto.setSpec(ordersDto.getSpec());
        Cart cart;
        try{
            cart = cartService.addCart(cartDto);
        }catch (BusinessException b){
            throw new BusinessException(CodeMsg.CART_NOT_REPEAT, "该商品已购买或已生成订单!");
        }
        ordersDto.setCartIdList(Arrays.asList(cart.getId()));
        return addOrder(ordersDto);
    }

    /**
     * 检验订单是否已支付
     * @param orderNumber 订单号
     * @return 0未支付 1已支付
     */
    public Integer getOrderPayStatus(String orderNumber){
        return ordersRepository.findAllByOrderNumber(orderNumber).getPayState();
    }

    //创建订单的基本信息(用户/状态/编号)
    public Orders createBasisOrders(AppUser user) {
        Orders orders = new Orders();
        orders.setUserId(user.getId());
        orders.setUserPhone(user.getPhone());
        //订单编号
        StringBuffer orderNo = null;
        Orders exist = null;
        do {
            try {
                orderNo = OrderNoUtil.generateOrderNo(user.getPhone());
            } catch (Exception e) {
                log.error("订单编号生成错误:{} \r\n 堆栈信息:{}", e.getMessage(), BusinessException.collectExceptionStackMsg(e));
                throw new BusinessException(CodeMsg.SYSTEM_ERR);
            }
            if (orderNo == null) {
                throw new BusinessException(CodeMsg.ORDERS_NO_CREATE_FAIL);
            }
            exist = ordersRepository.findByOrderNo(orderNo.toString());
        } while (exist != null);
        //基础信息
        orders.setNo(orderNo.toString());//单号
        orders.setSendPath(sendPathService.getDefaultByPhone(user.getPhone()));
        orders.setOrdersState(WZCL.ORDER_STATE.PROCESSING);    //订单打开
        orders.setPayState(WZCL.PAY_STATE.UNPAID);             //待支付
        orders.setDeliveryState(WZCL.DELIVERY_STATE.INITIAL);  //初始状态
        orders.setState(WZCL.STATE.NOT_DELETE);                //未删除
        return orders;
    }


    @Override
    public Orders delOrderById(Integer id) {
        //校验获得
        Orders order = getAndCheckById(id);
        //删除订单需要验证用户
        String phone = SecurityContextHolder.getContext().getAuthentication().getName();
        if (!phone.equals(order.getUserPhone())) {
            throw new BusinessException(CodeMsg.USER_NOT_MATCH);
        }
        //用户仅支持取消(状态->待支付/支付失败-订单打开-初始状态)的订单
        if (order.getOrdersState().equals(WZCL.ORDER_STATE.PROCESSING) &&
                (order.getPayState().equals(WZCL.PAY_STATE.UNPAID) || order.getPayState().equals(WZCL.PAY_STATE.PAY_FAIL))) {
            delOrder(order);
            return order;
        }
        throw new BusinessException(CodeMsg.ORDER_OPERATE_FAIL, "当前订单无法取消");
    }

    @Override
    public void delOrder(Orders order) {
        //恢复购物车
        cartService.restoreCartByOrders(order);
        //删除支付记录
        // TODO 支付记录哈哈哈
        //payRecordService.delPayRecordByOrderNo(order.getNo());
        //删除order
        ordersRepository.delete(order);
    }


    @Override
    public Orders updateOrder(OrdersDto ordersDto) {
        //仅允许修改收货地址
        //仅支持物流状态为初始状态/待发货的时候才能修改
        if (ordersDto.getSendPathId() != null) {
            //校验获取
            Orders order = getAndCheckById(ordersDto);
            //修改订单需要验证用户
            String phone = SecurityContextHolder.getContext().getAuthentication().getName();
            if (!phone.equals(order.getUserPhone())) {
                throw new BusinessException(CodeMsg.USER_NOT_MATCH);
            }
            if (WZCL.DELIVERY_STATE.INITIAL.equals(order.getDeliveryState()) || WZCL.DELIVERY_STATE.BE_DELIVER.equals(order.getDeliveryState())) {
                //无修改直接返回
                if (order.getSendPath() != null && ordersDto.getSendPathId().equals(order.getSendPath().getId())) {
                    log.info("Order ID:{} sendPath has not changed,pass this request", order.getId());
                    return order;
                }
                SendPath sendPath = sendPathService.getAndCheckById(ordersDto.getSendPathId());
                order.setSendPath(sendPath);
                return ordersRepository.save(order);
            }
            throw new BusinessException(CodeMsg.ORDER_OPERATE_FAIL, "当前订单无法修改收货地址");
        }
        return null;
    }


    @Override
    public Orders getOrderById(Integer id) {
        return ordersRepository.findById(id).orElse(null);
    }


    @Override
    public Orders getAndCheckById(Integer id) {
        if (id == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少订单Id");
        }
        Orders order = getOrderById(id);
        if (order == null) {
            throw new BusinessException(CodeMsg.ORDERS_NOT_EXIST);
        }
        return order;
    }

    @Override
    public Orders getAndCheckByNo(String no) {
        if (StringUtils.isBlank(no)) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少订单编号");
        }
        Orders order = ordersRepository.findByOrderNo(no);
        if (order == null) {
            throw new BusinessException(CodeMsg.ORDERS_NOT_EXIST);
        }
        return order;
    }

    @Override
    public List<Orders> getOrderList(OrdersDto ordersDto) {
        return ordersRepository.findAll(getSpecification(ordersDto), ordersDto.getSort());
    }

    @Override
    public MyPage<Orders> getOrderPage(OrdersDto ordersDto) throws NoSuchMethodException {
        List<Orders> all = ordersRepository.findAll(getSpecification(ordersDto));
        for (int index = 0; index < all.size(); index++) {
            //获取用户名
            AppUser appUser = appUserRepository.findByPhone(all.get(index).getUserPhone());
            String realName = appUser.getRealName();
            all.get(index).setUserName(realName);
        }
        ArrayList<Orders> content = new ArrayList<>(all);
        //排序
        List<Orders> listBySort = CollectionUtil.getListBySort(content, "getUpdateTime", "desc");
        // 分页
        List<Orders> list = CollectionUtil.getListByPage(listBySort, ordersDto.getPageNumber()+1, ordersDto.getPageSize());
        MyPage<Orders> myPage = new MyPage<>();
        myPage.setContent(list);
        myPage.setTotalElements(all.size());
        return myPage;
    }

    //订单支付
    @Override
    public String payOrder(OrdersDto ordersDto) {
        if (ordersDto == null || ordersDto.getId() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "缺少订单信息");
        }
        if (LockUtil.isLocked(PAY_LOCK + ordersDto.getId())) {
            throw new BusinessException(CodeMsg.ORDER_CREATING);
        }
        try {
            LockUtil.lock(PAY_LOCK + ordersDto.getId(), 5 * 60);
            //校验获取
            Orders order = getAndCheckById(ordersDto);
            //送货地址校验
            if (order.getSendPath() == null) {
                throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "请先填写配送地址");
            }
            //用户校验
            String phone = SecurityContextHolder.getContext().getAuthentication().getName();
            if (!order.getUserPhone().equals(phone)) {
                throw new BusinessException(CodeMsg.USER_NOT_MATCH);
            }
            if (WZCL.PAY_STATE.PAY_FAIL.equals(order.getPayState()) || WZCL.PAY_STATE.UNPAID.equals(order.getPayState())) {
                //拉起支付
                if (redisUtil.hasKey(PAY_KEY + order.getNo() + "_" + ordersDto.getPayType())) {
                    return redisUtil.get(PAY_KEY + order.getNo() + "_" + ordersDto.getPayType()) + "";
                }
                MyPayService payService = PayServiceFactory.makePayService(ordersDto.getPayType());
                String pay = payService.appPay(order, order.getPayMoney(), "望子成龙订单—" + order.getNo(), ordersDto.getIp());
                redisUtil.set(PAY_KEY + order.getNo() + "_" + ordersDto.getPayType(), pay, 15 * 60);
                //更改订单的支付类型
                if (ordersDto.getPayType() == 0){
                    ordersRepository.updateSysType(2, order.getNo());
                }
                if (ordersDto.getPayType() == 1){
                    ordersRepository.updateSysType(1, order.getNo());
                }
                log.info(pay);
                return pay;
            }
            throw new BusinessException(CodeMsg.ORDER_OPERATE_FAIL, "当前订单无需支付");
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("订单支付失败:{} \r\n 堆栈信息:{}", e.getMessage(), BusinessException.collectExceptionStackMsg(e));
            throw new BusinessException(CodeMsg.SYSTEM_ERR);
        } finally {
            LockUtil.unlock(PAY_LOCK + ordersDto.getId());
        }
    }

    //更改快递状态
    @Override
    public void changeDeliveryState(String orderNo, Integer deliveryState) {
        //校验获取
        Orders orders = getAndCheckByNo(orderNo);
        //修改收货状态
        if (WZCL.DELIVERY_STATE.RECEIVED.equals(deliveryState)) {
            //已收货-> 支付完成-订单完成-已收货
            orders.setOrdersState(WZCL.ORDER_STATE.COMPLETED);
        }
        if (WZCL.DELIVERY_STATE.RETURNS_BE_RECEIVED.equals(deliveryState)) {
            //商家待收货-> 待退款-订单完成-商家待收货
            orders.setPayState(WZCL.PAY_STATE.BE_REFUND);
        }
        orders.setDeliveryState(deliveryState);
        log.info("更新订单NO{}的物流状态：{}", orderNo, deliveryState);
        ordersRepository.save(orders);
    }

    @Override
    public void setPayStateByOrderNo(Integer payState, String orderNo) {
        ordersRepository.setPayStateByNo(payState, orderNo);
    }

    @Override
    public void setPayStateAndOrderStateByOrderNo(Integer payState, Integer orderState, String orderNo) {
        ordersRepository.setPayStateAndOrdersStateByNo(payState, orderState, orderNo);
    }

    @Override
    public Orders seckillCheck(AppUser user, String commodityId, String activityId, String spec) {
        //校验是否重复秒杀
        String createFrom = new StringBuffer(SECKILL_TYPE_KEY).append("_")
                .append(commodityId).append("_")
                .append(activityId).toString();
        Orders orders = ordersRepository.findByUserPhoneAndCreateFrom(user.getPhone(), createFrom);
        if (orders != null) {
            throw new BusinessException(CodeMsg.ACTIVITY_HAS_PARTICIPATED);
        }
        //检验商品可否秒杀
        Commodity commodity = commodityService.getCommodityById(Integer.valueOf(commodityId));
        Specifications specifications = null;
        if (commodity.getSpec()) {
            specifications = specificationsService.getByCommodityIdAndSpec(commodity.getId(), spec);
            if (specifications == null) {
                throw new BusinessException(CodeMsg.SYSTEM_ERR, "当前规格商品已不存在,请重新选购");
            }
        }
        if (WZCL.COMMODITY_TYPE.COURSE.equals(commodity.getType())) {
            UserCourse course = null;
            course = userCourseService.findByPhoneAndCourseIdAndSpec(user.getPhone(), commodity.getResourceId(), spec);
            if (course != null) {
                throw new BusinessException(CodeMsg.USER_COURSE_HAS_EXIST);
            }
        }
        Activity activity = activityService.getAndCheckById(Integer.valueOf(activityId));
        //校验用户是否享受活动
        if (!activityService.checkActivity(user, activity, new HashMap<>())) {
            throw new BusinessException(CodeMsg.ACTIVITY_USER_CANNOT_PARTICIPATED);
        }
        //同步创建订单
        Orders order = createBasisOrders(user);
        order.setCreateFrom(createFrom);
        //创建订单详情
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setCommodity(commodity);
        orderDetail.setOldPrice(commodity.getOldPrice());
        orderDetail.setSpec(spec);
        orderDetail.setCurrentPrice(specifications == null ? commodity.getCurrentPrice() : specifications.getPrice());
        //计算出需要支付的价格
        BigDecimal pay = activityService.getFactoryByType(WZCL.ACTIVITY_TYPE.SECKILL).computePrice(activity, orderDetail.getCurrentPrice(), createFrom);
        orderDetail.setPay(pay);
        order.setDetails(Arrays.asList(orderDetail));
        order.setMoney(orderDetail.getOldPrice());
        order.setProductMoney(orderDetail.getCurrentPrice());
        order.setNeedDelivery(commodity.getNeedDelivery());
        order.setPayMoney(pay);
        Orders basisOrder = ordersRepository.save(order);
        //生成唯一对应的支付记录
        // TODO 支付记录哈哈哈
        //payRecordService.initPayRecordByOrder(basisOrder);
        //免费则发送支付回调
        if (BigDecimal.ZERO.compareTo(basisOrder.getPayMoney()) == 0) {
            // TODO 支付记录哈哈哈
            /*PayRecord payRecord = new PayRecord();
            payRecord.setOrderNo(basisOrder.getNo());
            payRecord.setPay(BigDecimal.ZERO);
            payRecord.setPayTime(new Date());
            payRecord.setPayType(WZCL.PAY_TYPE.FREE);
            payRecord.setPayState(WZCL.PAY_STATE.PAID);*/
            // TODO 支付记录哈哈哈
            //amqpTemplate.convertAndSend(RabbitMqConfiguration.DIRECT_QUEUE_PAID, JSON.toJSONString(payRecord));
        } else {
            //设置过期时间
            amqpTemplate.convertAndSend(RabbitMqConfiguration.DELAY_QUEUE_ORDER, basisOrder.getNo());
        }
        return basisOrder;
    }

    @Override
    public Orders groupCheck(AppUser user, Integer commodityId, Integer activityId, Integer promotionId, String spec, Integer groupId) {
        //校验是否重复拼团
        String createFrom = new StringBuffer(GROUP_TYPE_KEY).append("_")
                .append(commodityId).append("_")
                .append(activityId)
                .append(":")
                .toString();
        List<Orders> list = ordersRepository.findAllByUserPhoneAndCreateFromLike(user.getPhone(), createFrom + "%");
        if (list != null && list.size() > 0) {
            throw new BusinessException(CodeMsg.ACTIVITY_HAS_PARTICIPATED);
        }
        Map<String, Integer> map = new LinkedHashMap<>(4);
        if (groupId != null) {
            ActivityGroup activityGroup = activityGroupService.getAndCheckById(groupId);
            if (activityGroup.getSize() + 1 > activityGroup.getMax()) {
                throw new BusinessException(CodeMsg.ACTIVITY_USER_CANNOT_PARTICIPATED, "当前团已满");
            }
            if (!activityGroup.getGroupState().equals(WZCL.GROUP_STATE.PROCESSING)) {
                throw new BusinessException(CodeMsg.ACTIVITY_USER_CANNOT_PARTICIPATED, "当前团已成团或已过期");
            }
            map.put(OrderServiceImpl.GROUP_PARAMETER_GROUP_ID, groupId);
        }
        map.put(OrderServiceImpl.GROUP_PARAMETER_PROMOTION_ID, promotionId);
        createFrom = createFrom + JSON.toJSONString(map);
        //检验商品可否拼团
        Commodity commodity = commodityService.getCommodityById(commodityId);
        Specifications specifications = null;
        if (commodity.getSpec()) {
            specifications = specificationsService.getByCommodityIdAndSpec(commodity.getId(), spec);
            if (specifications == null) {
                throw new BusinessException(CodeMsg.SYSTEM_ERR, "当前规格商品已不存在,请重新选购");
            }
        }
        if (WZCL.COMMODITY_TYPE.COURSE.equals(commodity.getType())) {
            UserCourse course = null;
            course = userCourseService.findByPhoneAndCourseIdAndSpec(user.getPhone(), commodity.getResourceId(), spec);
            if (course != null) {
                throw new BusinessException(CodeMsg.USER_COURSE_HAS_EXIST);
            }
        }
        Activity activity = activityService.getAndCheckById(activityId);
        //校验用户是否享受活动
        if (!activityService.checkActivity(user, activity, new HashMap<>())) {
            throw new BusinessException(CodeMsg.ACTIVITY_USER_CANNOT_PARTICIPATED);
        }
        //同步创建订单
        Orders order = createBasisOrders(user);
        order.setCreateFrom(createFrom);
        //创建订单详情
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setCommodity(commodity);
        orderDetail.setOldPrice(commodity.getOldPrice());
        orderDetail.setSpec(spec);
        orderDetail.setCurrentPrice(specifications == null ? commodity.getCurrentPrice() : specifications.getPrice());
        //计算出需要支付的价格
        BigDecimal pay = activityService.getFactoryByType(WZCL.ACTIVITY_TYPE.GROUP).computePrice(activity, orderDetail.getCurrentPrice(), createFrom);
        orderDetail.setPay(pay);
        order.setDetails(Arrays.asList(orderDetail));
        order.setMoney(orderDetail.getOldPrice());
        order.setProductMoney(orderDetail.getCurrentPrice());
        order.setNeedDelivery(commodity.getNeedDelivery());
        order.setPayMoney(pay);
        order = ordersRepository.save(order);
        // TODO 支付记录哈哈哈
        //payRecordService.initPayRecordByOrder(order);
        if (BigDecimal.ZERO.compareTo(order.getPayMoney()) == 0) {
            // TODO 支付记录哈哈哈
            /*PayRecord payRecord = new PayRecord();
            payRecord.setOrderNo(order.getNo());
            payRecord.setPay(BigDecimal.ZERO);
            payRecord.setPayTime(new Date());
            payRecord.setPayType(WZCL.PAY_TYPE.FREE);
            payRecord.setPayState(WZCL.PAY_STATE.PAID);*/
            // TODO 支付记录哈哈哈
            //amqpTemplate.convertAndSend(RabbitMqConfiguration.DIRECT_QUEUE_PAID, JSON.toJSONString(payRecord));
        } else {
            //设置过期时间这个订单的过期时间不是团的过期时间
            amqpTemplate.convertAndSend(RabbitMqConfiguration.DELAY_QUEUE_ORDER, order.getNo());
        }
        return order;
    }


    //消费回调
    @Transactional
    @RabbitListener(queues = RabbitMqConfiguration.DIRECT_QUEUE_PAID)
    public void OrderPayConsumer(String payRecordStr) {
        log.info("mq:{} received massage：{}", RabbitMqConfiguration.DIRECT_QUEUE_PAID, payRecordStr);
        PayRecord payRecordMsg = JSON.parseObject(payRecordStr, PayRecord.class);
        //支付记录
        // TODO 支付记录哈哈哈
        //PayRecord payRecord = payRecordService.getByOrderNo(payRecordMsg.getOrderNo());
        // TODO 支付记录哈哈哈
        /*if(payRecord == null){
            log.warn("找不到当前订单记录,No{{}}记录不做处理",payRecordMsg.getOrderNo());
            return;
        }*/
        // TODO 支付记录哈哈哈
        //Orders orders = getAndCheckByNo(payRecordMsg.getOrderNo());
        //订单中的课程
        Map<Integer, Course> courseMap = new HashMap<>();
        Map<Integer, Set<String>> specMap = new HashMap<>();
        // TODO 支付记录哈哈哈
        /*List<OrderDetail> details = orders.getDetails();
        for (OrderDetail detail : details) {
            if (WZCL.COMMODITY_TYPE.COURSE.equals(detail.getCommodity().getType())) {
                Course course = courseService.getAndCheckByCommodityId(detail.getCommodity().getId());
                //商品id找对应的课程
                courseMap.put(course.getId(), course);
                Set<String> set = specMap.get(course.getId());
                if (set == null) {
                    Set<String> newSet = new HashSet<>();
                    newSet.add(detail.getSpec());
                    specMap.put(course.getId(), newSet);
                } else {
                    set.add(detail.getSpec());
                }
            }
        }
        //已支付
        if (WZCL.PAY_STATE.PAID.equals(payRecordMsg.getPayState())) {
            //支付记录修改
            BeanUtils.copyProperties(payRecordMsg, payRecord, "id", "createTime", "updateTime", "state");
            if (orders.getCreateFrom().startsWith(GROUP_TYPE_KEY)) {
                orders.setPayState(WZCL.PAY_STATE.PAID_FOR_GROUP);
            } else {
                //订单状态修改
                orders.setPayState(WZCL.PAY_STATE.PAID);
                //将购买的课程写入用户课程库
                if (specMap.size() > 0) {
                    AppUser user = userService.getUserByPhone(orders.getUserPhone());
                    userCourseService.addUserCourseByMap(user, courseMap, specMap);
                }
                //删除购物车
                cartService.delCartByOrders(orders);
                //更改订单状态
                if (orders.getNeedDelivery()) {
                    //有发货需求：状态->支付成功-订单打开-待发货
                    orders.setDeliveryState(WZCL.DELIVERY_STATE.BE_DELIVER);
                    //发货请求放入MQ
                    amqpTemplate.convertAndSend(RabbitMqConfiguration.DIRECT_QUEUE_PATH, JSON.toJSONString(orders));
                } else {
                    //无发货需求：状态->支付成功-订单完成-初始状态
                    orders.setOrdersState(WZCL.ORDER_STATE.COMPLETED);
                }
            }
        }//退款
        else if (WZCL.PAY_STATE.REFUNDED.equals(payRecordMsg.getPayState())) {
            if (orders.getPayState().equals(WZCL.PAY_STATE.PAID_FOR_GROUP)) {
                //未成团过期订单 -> 删除数据信息,防止无法再次拼团
                orders.setCreateFrom(GROUP_TYPE_KEY);
            } else {
                //将购买的课程移除用户课程库
                if (specMap.size() > 0) {
                    AppUser user = userService.getUserByPhone(orders.getUserPhone());
                    userCourseService.delUserCourseByMap(user, courseMap, specMap);
                }
            }
            //订单状态修改
            orders.setPayState(WZCL.PAY_STATE.REFUNDED);
            //修改记录内容
            payRecord.setPayState(WZCL.PAY_STATE.REFUNDED);
            payRecord.setRefundTradeNo(payRecordMsg.getRefundTradeNo());
            //状态->已退款-订单关闭-X
            orders.setOrdersState(WZCL.ORDER_STATE.CLOSED);
        } else {
            return;
        }
        ordersRepository.save(orders);
        payRecordService.saveRecord(payRecord);
        if (orders.getCreateFrom().startsWith(GROUP_TYPE_KEY)) {
            amqpTemplate.convertAndSend(RabbitMqConfiguration.DIRECT_QUEUE_GROUP, orders.getNo());
        }*/
    }

    @Transactional
    @RabbitListener(queues = RabbitMqConfiguration.DEAD_QUEUE_ORDER)
    public void orderExpired(String orderNo) {
        log.info("mq:{} received massage：{}", RabbitMqConfiguration.DEAD_QUEUE_ORDER, orderNo);
        Orders orders = ordersRepository.findByOrderNo(orderNo);
        if (orders != null && (WZCL.PAY_STATE.UNPAID.equals(orders.getPayState()) || WZCL.PAY_STATE.PAY_FAIL.equals(orders.getPayState()))) {
            log.info("The order NO:{} has expired", orderNo);
            delOrder(orders);
        }
    }


    private Specification<Orders> getSpecification(OrdersDto ordersDto) {
        return new Specification<Orders>() {
            @Override
            public Predicate toPredicate(Root<Orders> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<Predicate>();
                if (StringUtils.isNotBlank(ordersDto.getNo())) {
                    predicates.add(criteriaBuilder.like(root.get("no"), "%" + ordersDto.getNo() + "%"));
                }
                if (StringUtils.isNotBlank(ordersDto.getUserPhone())) {
                    predicates.add(criteriaBuilder.equal(root.get("userPhone"), ordersDto.getUserPhone()));
                }
                if (ordersDto.getPayState() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("payState"), ordersDto.getPayState()));
                }
                if (ordersDto.getOrdersState() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("ordersState"), ordersDto.getOrdersState()));
                }
                if (ordersDto.getDeliveryState() != null) {
                    predicates.add(criteriaBuilder.equal(root.get("deliveryState"), ordersDto.getDeliveryState()));
                }
                if (ordersDto.getSysType() != null){
                    predicates.add(criteriaBuilder.equal(root.get("sysType"), ordersDto.getSysType()));
                }
                predicates.add(criteriaBuilder.equal(root.get("state"), WZCL.STATE.NOT_DELETE));
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
    }


    /**
     * 计算商品活动对商品的改变
     *
     * @param orders 订单
     * @param user   用户
     * @param carts  购物车
     */
    public List<OrderDetail> computeOrderDetails(Orders orders, AppUser user, Cart... carts) {
        //order相关
        List<OrderDetail> orderDetails = new ArrayList<>();
        //快递信息
        Boolean needDelivery = false;
        //用来完成整个数据的交互
        HashMap<String, Object> data = new HashMap<>();
        //处理同一活动的活动关系
        HashMap<Integer, List<OrderDetail>> contain = new HashMap<>();
        //单品活动在便利的时候直接处理
        HashMap<Integer, Activity> activityMap = new HashMap<>(); //非单品活动的集合

        List<Commodity> commodityList = new ArrayList<>();
        //活动计算的优先级 单品 -> 同活动 -> 整单
        //1.1处理单品活动
        for (Cart cart : carts) {
            Commodity commodity = cart.getCommodity();
            commodityService.check(commodity);
            commodityList.add(commodity);
            //-----------校验快递信息----------
            if (!needDelivery && commodity.getNeedDelivery()) {
                needDelivery = true;
            }
            //处理计算单品数据同时创建详情
            OrderDetail orderDetail = handleSingleAndCreateDetail(commodity, cart.getSpec(), user, data, orders.getCreateFrom(), contain, activityMap);
            //-----------放入集合---------------
            orderDetails.add(orderDetail);
        }
        commodityService.decreaseStock(commodityList.toArray(new Commodity[0]));
        //1.2计算order的价格 方便后续处理
        BigDecimal money = new BigDecimal("0");//商品价值（原价）
        BigDecimal productMoney = new BigDecimal("0");//计算商品价格(现价)
        BigDecimal payMoney = new BigDecimal("0");//实际应付
        for (OrderDetail orderDetail : orderDetails) {
            money = money.add(orderDetail.getOldPrice());
            productMoney = productMoney.add(orderDetail.getCurrentPrice());
            payMoney = payMoney.add(orderDetail.getPay());
        }
        //2.处理同活动范围的活动优惠
        if (!contain.isEmpty()) {
            //吧未处理的同范围的活动提出来,同时移除
            ArrayList<Activity> activityList = new ArrayList<>();
            for (Integer integer : contain.keySet()) {
                activityList.add(activityMap.remove(integer));
            }
            //对同活动排序后处理
            Collections.sort(activityList, (o1, o2) -> o2.getOrderNo() - o1.getOrderNo());
            for (Activity activity : activityList) {
                //需要支付的价格
                BigDecimal payDecimal = new BigDecimal("0");
                //获取需要打折的订单(订单详情)
                List<OrderDetail> detailList = contain.get(activity.getId());
                for (OrderDetail orderDetail : detailList) {
                    payDecimal = payDecimal.add(orderDetail.getPay());
                }
                //记录一下减价前需要支付的价格
                BigDecimal pay = payDecimal;
                //执行打折
                if (activityService.checkActivity(user, activity, data)) {
                    payDecimal = activityService.getFactoryByType(activity.getType()).computePrice(activity, payDecimal, orders.getCreateFrom());
                }
                //总支付价格减去需要减的价格
                payMoney = payMoney.subtract(pay.subtract(payDecimal));
            }
        }
        //3.计算总单的价格
        if (!activityMap.isEmpty()) {
            List<Activity> activityList = Arrays.asList(activityMap.values().toArray(new Activity[0]));
            Collections.sort(activityList, (o1, o2) -> o2.getOrderNo() - o1.getOrderNo());
            for (Activity activity : activityList) {
                if (activityService.checkActivity(user, activity, data)) {
                    payMoney = activityService.getFactoryByType(activity.getType()).computePrice(activity, payMoney, orders.getCreateFrom());
                }
            }
        }
        orders.setMoney(money);
        orders.setProductMoney(productMoney);
        orders.setPayMoney(payMoney);
        orders.setNeedDelivery(needDelivery);
        return orderDetails;
    }


    public OrderDetail handleSingleAndCreateDetail(Commodity commodity, String spec, AppUser user, HashMap<String, Object> data, String orderFrom, HashMap<Integer, List<OrderDetail>> contain, HashMap<Integer, Activity> activityMap) {
        //-----------创建订单详情----------
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setCommodity(commodity);
        orderDetail.setOldPrice(commodity.getOldPrice());
        orderDetail.setSpec(spec);
        if (StringUtils.isNotBlank(spec)) {
            Specifications specifications = specificationsService.getByCommodityIdAndSpec(commodity.getId(), spec);
            if (specifications == null) {
                throw new BusinessException(CodeMsg.SYSTEM_ERR, "当前规格商品已不存在,请重新选购");
            }
            orderDetail.setSpec(specifications.getSpec());
            orderDetail.setCurrentPrice(specifications.getPrice());
        } else {
            orderDetail.setCurrentPrice(commodity.getCurrentPrice());
        }
        //计算出需要支付的价格
        BigDecimal currentPrice = orderDetail.getCurrentPrice();
        //------------计算活动优惠-----------------
        List<Activity> activityList = commodity.getActivityList();
        if (activityList != null && activityList.size() > 0) {
            for (Activity activity : activityList) {
                //------------作用于单品-------------
                if (WZCL.ACTIVITY_SCOPE.SINGLE.equals(activity.getScope())) {
                    //直接计算作用于单品的活动
                    //------------满足活动规则-------------
                    if (activityService.checkActivity(user, activity, data)) {
                        currentPrice = activityService.getFactoryByType(activity.getType()).computePrice(activity, currentPrice, orderFrom);
                    }
                    //------------作用于同一活动的商品-------------
                } else {
                    //将商品关系存入
                    if (WZCL.ACTIVITY_SCOPE.CONTAIN.equals(activity.getScope()))
                        if (contain.containsKey(activity.getId())) {
                            contain.get(activity.getId()).add(orderDetail);
                        } else {
                            ArrayList<OrderDetail> list = new ArrayList<>();
                            list.add(orderDetail);
                            contain.put(activity.getId(), list);
                        }
                    activityMap.put(activity.getId(), activity);
                }
            }
        }
        //目前把现价当需要支付的价格
        orderDetail.setPay(currentPrice);
        return orderDetail;
    }

    //拼团订单变更回调
    @Transactional
    @RabbitListener(queues = RabbitMqConfiguration.DIRECT_QUEUE_GROUP)
    public void OrderGroupConsumer(String orderNo) {
        log.info("mq:{} received massage：{}", RabbitMqConfiguration.DIRECT_QUEUE_GROUP, orderNo);
        Orders orders = ordersRepository.findByOrderNo(orderNo);
        String createFrom = orders.getCreateFrom();
        AppUser user = userService.getUserByPhone(orders.getUserPhone());
        if (orders.getPayState().equals(WZCL.PAY_STATE.PAID_FOR_GROUP)) {
            //付款开团，参团
            int index = createFrom.indexOf(":");
            String messageStr = createFrom.substring(0, index);
            String[] message = messageStr.split("_");
            String commodityId = message[1];
            String parameter = createFrom.substring(index + 1);
            Map map = JSON.parseObject(parameter);
            Integer promotionId = (Integer) map.get(GROUP_PARAMETER_PROMOTION_ID);
            Object groupId = map.get(GROUP_PARAMETER_GROUP_ID);
            if (groupId != null) {
                //参团
                ActivityGroup group = activityGroupService.joinActivityGroup(user, (Integer) groupId);
                if (group.getMax() <= group.getSize()) {
                    //拼团成功
                    groupSuccess(group);
                }
            } else {
                //开团
                ActivityGroup activityGroup = activityGroupService.createActivityGroup(user, promotionId, Integer.valueOf(commodityId));
                LinkedHashMap<String, Integer> linkedHashMap = new LinkedHashMap<>(4);
                linkedHashMap.put(GROUP_PARAMETER_GROUP_ID, activityGroup.getId());
                linkedHashMap.put(GROUP_PARAMETER_PROMOTION_ID, promotionId);
                String newCreateFrom = new StringBuffer(messageStr).append(":").append(JSON.toJSONString(linkedHashMap)).toString();
                orders.setCreateFrom(newCreateFrom);
                ordersRepository.save(orders);
            }
        }
    }

    //拼团成功的操作
    public void groupSuccess(ActivityGroup group) {
        String createFrom = new StringBuffer(GROUP_TYPE_KEY).append("_")
                .append(group.getCommodityId()).append("_")
                .append(group.getActivityId())
                .append(":")
                .append("%")
                .toString();
        //获取参与这个活动的且已支付的所有订单
        List<Orders> orderList = ordersRepository.findAllByCreateFromLike(createFrom);
        //过滤出非这个团中的订单
        orderList.stream().filter(orders -> orders.getCreateFrom().contains(String.format("\"%s\":%d", GROUP_PARAMETER_GROUP_ID, group.getId())))
                .forEach(orders -> {
                    //订单中的课程
                    Map<Integer, Course> courseMap = new HashMap<>();
                    Map<Integer, Set<String>> specMap = new HashMap<>();
                    List<OrderDetail> details = orders.getDetails();
                    for (OrderDetail detail : details) {
                        if (WZCL.COMMODITY_TYPE.COURSE.equals(detail.getCommodity().getType())) {
                            Course course = courseService.getAndCheckByCommodityId(detail.getCommodity().getId());
                            //商品id找对应的课程
                            courseMap.put(course.getId(), course);
                            Set<String> set = specMap.get(course.getId());
                            if (set == null) {
                                Set<String> newSet = new HashSet<>();
                                newSet.add(detail.getSpec());
                                specMap.put(course.getId(), newSet);
                            } else {
                                set.add(detail.getSpec());
                            }
                        }
                        //订单状态修改
                        //orders.setPayState(WZCL.PAY_STATE.PAID);
                        //将购买的课程写入用户课程库
                        if (specMap.size() > 0) {
                            AppUser user = userService.getUserByPhone(orders.getUserPhone());
                            userCourseService.addUserCourseByMap(user, courseMap, specMap);
                        }
                        //更改订单状态
                        if (orders.getNeedDelivery()) {
                            //有发货需求：状态->支付成功-订单打开-待发货
                            orders.setDeliveryState(WZCL.DELIVERY_STATE.BE_DELIVER);
                            //发货请求放入MQ
                            amqpTemplate.convertAndSend(RabbitMqConfiguration.DIRECT_QUEUE_PATH, JSON.toJSONString(orders));
                        } else {
                            //无发货需求：状态->支付成功-订单完成-初始状态
                            orders.setOrdersState(WZCL.ORDER_STATE.COMPLETED);
                        }
                    }
                });
    }


    public List<Orders> findAllByCreateFromLike(String createFrom) {
        return ordersRepository.findAllByCreateFromLike(createFrom);
    }

    /**
     * 获取当前用户所有未支付订单
     * @return 用户信息
     */
    public RVO findAllNotPayByPayState(){
        //获取当前用户手机号
        String phone = SecurityContextHolder.getContext().getAuthentication().getName();
        //list对象转换
        List<IosOrdersDto> dtoList = new ArrayList<>();
        IosOrdersDto iosOrders = new IosOrdersDto();
        List<Orders> list = ordersRepository.findAllNotPayByPayState(phone);
        //将Orders转换为IosOrdersDto并封装到list
        for (int index = 0; index < list.size(); index++) {
            dtoList.add(BeanUtil.convertBean(list.get(index), iosOrders.getClass()));
        }

        if (list.size() == 0){
            return RVO.success(null);
        }
        return RVO.success(dtoList);
    }

    @Override
    @Transactional
    public RVO deleteByIds(List<Integer> ids) {
        if (ids.size() == 0){
            return RVO.error("传入id不能为空");
        }
        for (int index = 0; index < ids.size(); index++) {
            ordersRepository.deleteById(ids.get(index));
        }
        return RVO.success("删除成功");
    }

    @Override
    public MyPage retrieveByDate(OrdersDto ordersDto) {
        return new MyPage(ordersRepository.findAll(getSpecificationByDate(ordersDto), ordersDto.getPageable()));
    }

    //按时间查询账单条件过滤
    public Specification<Orders> getSpecificationByDate(OrdersDto ordersDto){
        return (Specification<Orders>) (root, criteriaQuery, criteriaBuilder) -> {
            ArrayList<Predicate> list = new ArrayList<>();
            if (ordersDto.getCreateTime() != null){
                //时间筛选
                String format = new SimpleDateFormat("yyyy-MM-dd").format(ordersDto.getCreateTime());
                //将日期转换为字符串进行模糊匹配查询当日订单(精确到日)
                list.add(criteriaBuilder.like(root.get("createTime").as(String.class), "%"+format+"%"));
            }
            if (ordersDto.getDate() != null){
                String format = new SimpleDateFormat("yyyy-MM").format(ordersDto.getDate());
                //将日期截取为年和月进行模糊匹配查询本月账单(精确到月)
                list.add(criteriaBuilder.like(root.get("createTime").as(String.class), "%"+format+"%"));
            }
            if (ordersDto.getSysType() != null){
                list.add(criteriaBuilder.equal(root.get("sysType"), ordersDto.getSysType()));
            }
            list.add(criteriaBuilder.equal(root.get("payState"), 1));
            // 排序
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createTime")));
            //将两个查询条件联合起来之后返回Predicate对象
            return criteriaBuilder.and(list.toArray(new Predicate[list.size()]));
        };
    }
}
